/*Implementação do metodo de monte carlo com threads*/

#include<stdio.h>
#include<stdlib.h>
#include<time.h> //pra semente do rand
#include<sys/time.h>
#include<gmp.h> //biblioteca pra obter precisao gigante
#include<pthread.h>

#define MAX_INT 1577  //numero de interacoes do metodo pré definido, se formos fazer por erro relativo o programa vai continuar rodando por algumas decadas, e provavelmente o computador vai ter quebrado antes de dar o resultado...
#define NUM_THREAD 8 //8 threads

mpf_t Pin; //variavel global que armazena o numero de pontos dentro do circulo

void* calculo_monte_carlo(void *interacao){

    mpf_t x, y, xquad, yquad, aux;

    mpf_init(x);
    mpf_init(y);
    mpf_init(aux);
    mpf_init(xquad);
    mpf_init(yquad);


    /*Calculo*/
    mpf_set_d(x, (double) rand());
    mpf_div_ui(x,x,RAND_MAX);
    mpf_set_d(y, (double) rand());
    mpf_div_ui(y,y,RAND_MAX);

    mpf_mul(xquad, x, x);
    mpf_mul(yquad, y, y);
    mpf_add(aux, xquad, yquad);
    if (mpf_cmp_d(aux,1.0) <= 0)
        mpf_add_ui(Pin, Pin, 1);


    mpf_clear(x);
    mpf_clear(y);
    mpf_clear(aux);
    mpf_clear(xquad);
    mpf_clear(yquad);
}


int main() {

    //VARIAVEIS PARA GUARDAR O TEMPO
    int tempo;
    struct timeval inicio, fim;


    unsigned long int i;
    unsigned long int j;
    mpf_t Pi, aux;
    pthread_t thread[NUM_THREAD];

    /*variaveis auxiliares*/
    mpf_init(aux);

    //SETAR A PRECISAO DO NUMERO DE CASAS DO TIPO DE DADOS MPG
    //EM BITS = (NUM_DIGITS * log2(10) ) = 33219281
    //ISSO EH NECESSARIO, POIS A PRECISAO DA FUNCAO MPG EH DADA EM VALOR DE BITS

    mpf_set_default_prec(33219281);
    // prec = 1/(10^PREC)


    mpf_init(Pi);
    mpf_init(Pin);

    //PEGA O TEMPO INICIAL DE EXECUCAO
    gettimeofday(&inicio, NULL);

    printf("RODANDO MÉTODO DE MONTE CARLO CONCORRENTE...\n");

    srand(time(0));
    j=0;
    while (j<MAX_INT) {
        for(i=0; i<NUM_THREAD; i++){
            printf("interacao: %ld\n", i+j);
            pthread_create(&thread[i], NULL, calculo_monte_carlo, NULL);
        }
        for(i=0; i<NUM_THREAD; i++)
            pthread_join(thread[i], NULL);
        j = j + NUM_THREAD;
    }

    mpf_div_ui(aux, Pin, j);
    mpf_mul_ui(Pi, aux, 4);

    //Fim do calculo

    //SALVA O PI EM UM ARQUIVO TXT
    FILE *fp = fopen("monte_carlo_concorrente.txt", "w");
    // IMPREIME COM PRECISAO  DE 10000000 DIGITOS*/
    mpf_out_str(fp, 10, 10000000, Pi);
    fclose(fp);

    //PEGA O TEMPO FINAL DE EXECUCAO
    gettimeofday(&fim, NULL);

    //DIFERENCA ENTRE FINAL E INICIAL
    tempo = fim.tv_sec - inicio.tv_sec;

    printf("COMPLETO\nITERACOES: %ld\n", j);
    printf("TEMPO DE EXECUÇÃO %d segundos\n", tempo);


    mpf_clear(Pi);
    mpf_clear(aux);
    mpf_clear(Pin);


    return 0;
}
